package org.erikaredmark.monkeyshines;
import java.util.HashMap;
import java.util.Map;
import org.erikaredmark.monkeyshines.bounds.Boundable;
/**
*
* Instance controlled immutable clipping rectangles. Rectangles taken from this class are immutable, and may be
* shared between multiple objects.
* <p/>
* This rectangles are designed for 'drawing Only!' not collision detection. Rectangle involved in collision detection
* should be mutable with regard to the object they are encompassing. This is used only for drawing. Objects created by the
* static factories are <strong>NEVER REMOVED FROM MEMORY UNTIL THE PROGRAM EXITS.</strong>. Given the size constraints of
* objects in the monkey shines world, there are only a small, finite number of possible clipping rectangles the program
* will ask for.
*
* @author Erika Redmark
*
*/
public final class ImmutableClippingRectangle extends Boundable {
// Caching: this class will only currently be used for clipping rectangles and drawing contexts. As a result, it will
// quickly fill up with (0, 0, 40, 40) and (40, 0, 40, 40) and valid rectangles for drawing sprites and fruits, and
// then no longer increase in size.
private static final Map<ImmutablePoint2D, Map<ImmutablePoint2D, ImmutableClippingRectangle> > availableInstances =
new HashMap<ImmutablePoint2D, Map<ImmutablePoint2D, ImmutableClippingRectangle> >();
// location -> size -> rectangle
private ImmutableClippingRectangle(final int x, final int y, final int width, final int height) {
this.location = ImmutablePoint2D.of(x, y);
this.size = ImmutablePoint2D.of(width, height);
}
/**
*
* Returns an instance of this object that is a clipping rectangle (immutable position and size) for the given
* co-ordinates. The returned instance may be shared among multiple objects.
*
* @param x
* x location
*
* @param y
* y location
*
* @param width
* width of rectangle
*
* @param height
* height of rectangle
*
* @return
* instance of this object with the given properties
*
*/
public static ImmutableClippingRectangle of(final int x, final int y, final int width, final int height) {
ImmutablePoint2D loc = ImmutablePoint2D.of(x, y);
ImmutablePoint2D siz = ImmutablePoint2D.of(width, height);
Map<ImmutablePoint2D, ImmutableClippingRectangle> validLoc =
availableInstances.get(loc);
if (validLoc == null) {
// no mapping for loc.
ImmutableClippingRectangle r = new ImmutableClippingRectangle(x, y, width, height);
// Create the inner hashmap size -> rectangle first
Map<ImmutablePoint2D, ImmutableClippingRectangle> newMap =
new HashMap<ImmutablePoint2D, ImmutableClippingRectangle>();
newMap.put(siz, r);
// The outer hashmap is already created. Create new entry for loc -> map[size -> rectangle]
availableInstances.put(loc, newMap);
return r;
} else {
// Mapping for loc -> map[size -> rectangle]. Check for valid size -> rectangle
ImmutableClippingRectangle r = validLoc.get(siz);
if (r == null) {
r = new ImmutableClippingRectangle(x, y, width, height);
validLoc.put(siz, r);
return r;
} else {
return r;
}
}
}
/**
*
* Returns an instance of this object based on the mutable clipping rectangle passed.
*
* @param c
*
* @return
*
*/
public static ImmutableClippingRectangle from(ClippingRectangle c) {
return of(c.x(), c.y(), c.width(), c.height() );
}
}